package com.neo.tiny.bpm.service.task;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.neo.tiny.bpm.dto.task.BpmProcessInstanceCreateReqDTO;
import com.neo.tiny.bpm.vo.instance.BpmProcessInstanceCreateReqVO;
import com.neo.tiny.bpm.vo.instance.BpmProcessInstancePageItemRespVO;
import com.neo.tiny.bpm.vo.instance.BpmProcessInstancePageReqVO;
import com.neo.tiny.bpm.vo.instance.BpmProcessInstanceRespVO;
import org.flowable.engine.delegate.event.FlowableCancelledEvent;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.ProcessInstance;

import javax.validation.Valid;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Description: 流程实例 Service 接口
 * @Author: yqz
 * @CreateDate: 2022/10/5 23:12
 */
public interface BpmProcessInstanceExtService {

    /**
     * 获得流程实例的分页
     *
     * @param userId    用户编号
     * @param pageReqVO 分页请求
     * @return 流程实例的分页
     */
    Page<BpmProcessInstancePageItemRespVO> getMyProcessInstancePage(Long userId, @Valid BpmProcessInstancePageReqVO pageReqVO);

    /**
     * 获得历史的流程实例
     *
     * @param id 流程实例的编号
     * @return 历史的流程实例
     */
    HistoricProcessInstance getHistoricProcessInstance(String id);


    /**
     * 创建流程实例（提供给前端）
     *
     * @param userId      用户编号
     * @param createReqVO 创建信息
     * @return 实例的编号
     */
    String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO);

    /**
     * 创建流程实例（提供给内部）
     *
     * @param userId       用户编号
     * @param createReqDTO 创建信息
     * @return 实例的编号
     */
    String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO);

    /**
     * 创建 ProcessInstance 拓展记录
     *
     * @param instance 流程任务
     */
    void createProcessInstanceExt(ProcessInstance instance);

    /**
     * 更新 ProcessInstance 拓展记录为取消
     *
     * @param event 流程取消事件
     */
    void updateProcessInstanceExtCancel(FlowableCancelledEvent event);

    /**
     * 更新 ProcessInstance 拓展记录为完成
     *
     * @param instance 流程任务
     */
    void updateProcessInstanceExtComplete(ProcessInstance instance);

    /**
     * 更新 ProcessInstance 拓展记录为不通过
     *
     * @param processInstanceId 流程编号
     * @param reason            理由。例如说，审批不通过时，需要传递该值
     */
    void updateProcessInstanceExtReject(String processInstanceId, String reason);

    /**
     * 获得流程实例 VO 信息
     *
     * @param instanceId 流程实例的编号
     * @return 流程实例
     */
    BpmProcessInstanceRespVO getProcessInstanceVO(String instanceId);

    /**
     * 获得流程实例
     *
     * @param id 流程实例的编号
     * @return 流程实例
     */
    ProcessInstance getProcessInstance(String id);


    /**
     * 获得流程实例列表
     *
     * @param ids 流程实例的编号集合
     * @return 流程实例列表
     */
    List<ProcessInstance> getProcessInstances(Set<String> ids);

    /**
     * 获得流程实例 Map
     *
     * @param ids 流程实例的编号集合
     * @return 流程实例列表 Map
     */
    default Map<String, ProcessInstance> getProcessInstanceMap(Set<String> ids) {
        List<ProcessInstance> list = getProcessInstances(ids);
        if (CollUtil.isEmpty(list)) {
            return new HashMap<>();
        }
        return list.stream()
                .collect(Collectors.toMap(ProcessInstance::getProcessInstanceId, Function.identity(), (key1, key2) -> key1));
    }

    /**
     * 获得历史的流程实例列表
     *
     * @param ids 流程实例的编号集合
     * @return 历史的流程实例列表
     */
    List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids);

    /**
     * 获得历史的流程实例 Map
     *
     * @param ids 流程实例的编号集合
     * @return 历史的流程实例列表 Map
     */
    default Map<String, HistoricProcessInstance> getHistoricProcessInstanceMap(Set<String> ids) {
        List<HistoricProcessInstance> list = getHistoricProcessInstances(ids);
        if (CollUtil.isEmpty(list)) {
            return new HashMap<>();
        }
        return list.stream()
                .collect(Collectors.toMap(HistoricProcessInstance::getId, Function.identity(), (key1, key2) -> key1));
    }
}
